package com.yazhuo.arrays;

import java.util.Arrays;
import java.util.NoSuchElementException;

public class DynamicArrayList<E> {
    private E[] data;
    // 记录当前元素个数
    private int size;
    // 默认容量
    private static final int INIT_CAP = 1;

    public DynamicArrayList(int initCapacity) {
        data = (E[]) new Object[initCapacity];
        this.size = 0;
    }

    public DynamicArrayList() {
        this(INIT_CAP);
    }

    public E add(E e) {
        final int cap = data.length;
        //检查是否需要扩容，满载
        if (cap == size) {
            resize(2 * cap);
        }
        // 在尾部插入元素
        data[size] = e;
        size++;
        return e;
    }

    /**
     * 在某一位置插入数据
     *
     * @param index index
     * @param e     item
     */
    public void add(int index, E e) {
        //检查目标索引是否越界
        checkPositionIndex(index);
        ////////////////////////////
        final int cap = data.length;
        //检查是否需要扩容，满载
        if (cap == size) {
            resize(2 * cap);
        }
        ////////////////////////////
        for (int i = size - 1; i >= index; i--) {
            data[i + 1] = data[i];
        }
        data[index] = e;
        size++;
    }

    public void addFirst(E e) {
        add(0, e);
    }


    public E removeFirst() {
        return remove(0);
    }

    public E removeLast() {
        if (size == 0) {
            throw new NoSuchElementException();
        }
        //尝试缩容
        final int cap = data.length;
        if (cap / 4 == size) {
            resize(cap / 2);
        }
        //尝试缩容
        final E targetValue = data[size - 1];
        data[size - 1] = null;
        size--;
        return targetValue;
    }

    public E remove(int index) {
        // 检查索引是否越界
        checkElementIndex(index);

        //尝试缩容
        final int cap = data.length;
        if (cap / 4 == size) {
            resize(cap / 2);
        }
        //尝试缩容

        final E targetValue = data[index];

        //搬数据
        for (int i = index + 1; i < size; i++) {
            data[i - 1] = data[i];
        }
        //抹掉最后一个
        data[size - 1] = null;
        size--;
        return targetValue;
    }

    public E set(int index, E e) {
        checkElementIndex(index);
        final E old = data[index];
        data[index] = e;
        return old;
    }

    public E get(int index) {
        checkElementIndex(index);
        return data[index];
    }

    public int getSize() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void resize(int newCap) {
        final E[] temp = (E[]) new Object[newCap];
        for (int i = 0; i < size; i++) {
            temp[i] = data[i];
        }
        data = temp;
    }

    /**
     * 是否是已经存在的元素索引
     *
     * @param index index
     * @return 是否是已经存在的元素索引
     */
    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

    /**
     * 检查这个位置是否可以存元素
     *
     * @param index index
     */
    private void checkElementIndex(int index) {
        if (!isElementIndex(index)) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size + " ,位置不能存元素");
        }
    }

    /**
     * 检查这个位置是否可以添加元素
     *
     * @param index index
     */
    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index)) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size + " ,位置不能添加元素");
        }
    }

    @Override
    public String toString() {
        return "DynamicArrayList{" +
                "data=" + Arrays.toString(data) +
                ", size=" + size +
                '}';
    }

    public static void main(String[] args) {
        final DynamicArrayList<Integer> integerDynamicArrayList = new DynamicArrayList<>(5);
        for (int i = 1; i <= 5; i++) {
            integerDynamicArrayList.add(i);
        }
        integerDynamicArrayList.add(5, 6);
        System.err.println(integerDynamicArrayList);
        integerDynamicArrayList.removeFirst();
        System.err.println(integerDynamicArrayList);
        integerDynamicArrayList.removeLast();
        System.err.println(integerDynamicArrayList);
        final Integer i = integerDynamicArrayList.get(1);
        System.err.println(i);
        integerDynamicArrayList.set(1, 10);
        System.err.println(integerDynamicArrayList);
    }
}
